Composites and Geometry Management

A contact which is the parent of another contact is known as a composite and is an instance of the composite subclass of contact objects. A composite may be the parent of another composite, leading to a tree-structured contact hierarchy. A contact is said to be an ancestor of another contact (its descendant) when it is its parent or an ancestor of its parent.

A composite represents a set of contacts which can be manipulated (positioned, presented, etc.) as a unit. A composite is useful whenever several contacts act in concert to provide a single component of the UI. Typical examples include ``control panels'' and ``dialog boxes'' — groups of contacts that are presented together and are used to make related adjustments to application data. The fundamental aspects of the contact parent-child relationship are the same as those of the window hierarchy defined by the X Window System. But in CLUE, a composite is also expected to act as the geometry manager for its child contacts; that is, to implement a style of layout for its children.

Here is how it works. A request to change the geometry of a contact is forwarded to the contact's parent, which actually performs the resulting change. It is important to understand that, due to its constraints, a geometry manager may not be able to perform a change as requested. For example, a request to increase the size of a contact might be refused if its geometry manager enforces a maximum size. Even if a requested change cannot be done, a geometry manager may be able to suggest a slightly different change which would be acceptable.

Placing geometry control in the hands of a geometry manager in this way has several advantages.

A composite's geometry management policy applies only to the set of its children which are managed. An unmanaged child is ignored by its geometry manager. Any geometry change to an unmanaged child is performed immediately as requested. However, changes to a managed child are arbitrated by its parent's geometry management policy. This can mean, for example, that a change to one child's position/size/priority can affect that of other children. Indeed, requesting a bigger size for a child might result in the parent asking its geometry manager to become bigger, leading to a ripple of geometry changes throughout the contact hierarchy.

How do you know if a contact is managed? This is determined by its state. A contact is managed if and only if its state is not :withdrawn. This means that a :mapped (and viewable) contact is managed. But there is also another possibility: a contact's state may also be :managed. This value represents the (rather rare) case of a contact which is not visible, but which is nevertheless taken into account by its geometry manager.

\framebox[5.5in]{
\hspace*{\fill}
{\bf Note}
\hspace*{\fill}
\parbox[t]{4.5in}{
An
unmanaged child can {\em never} be visible.}
\hspace*{\fill}}

Implementing geometry management is a topic for contact programmers only. If you define a new composite subclass, you will usually need to implement methods for the following three functions.